`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    17:01:46 09/27/2011 
// Design Name: 
// Module Name:    CPU_FSM
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module CPU_FSM(CLK, reset, SF_D, LCD_E, LCD_RS, LCD_RW);

`include "opcode.v"

input CLK;
input reset;
output [11:8] SF_D;
output LCD_E;
output LCD_RS;
output LCD_RW;

wire LCD_E, LCD_RS, LCD_RW;
wire [11:8] SF_D;


//Enables
reg wr_en,imm_en,regin_en,result_en,RAM_WE,IR_EN,PC_EN,PC_WE,PC_Jump,PSR_en;


//Connections
wire [4:0] F;
wire [3:0] reg1,reg2,write_address,lowerop;
wire [15:0] RAM_DO, IR, imm_data, B, result;
wire [9:0] RAM_ADDR, PC,PC_out, PC_in, PC_inc;

reg [3:0] state;

mux21 RAM_ADDR_mux(B[9:0],PC,RAM_ADDR,PC_EN);
mux21_16bit PC_mux(PC_inc,B[9:0],PC_in,PC_Jump);
mux21_4bit immediate_op_mux(IR[7:4],4'h0,lowerop,imm_en);

register16 IR_reg(RAM_DO,IR,IR_EN,reset,CLK);

//module Counter(CLK, reset, PC_in, PC_out, PC_inc, PC_WE);
Counter PC_module(CLK, reset, PC_in, PC_out, PC_inc, PC_WE);

assign PC = PC_out;
assign reg1 = IR[11:8];
assign reg2 = IR[3:0];
assign write_address = IR[11:8];
assign imm_data = {{8{1'b0}},IR[7:0]};


//module REG_ALU_LOGIC(CLK, reset, reg1, reg2, wr_en, write_address, op, regin_data, regin_en, result_en, imm_data, imm_en, F, result, B);
REG_ALU_LOGIC Reg_ALU(CLK, reset, reg1, reg2, wr_en, write_address, {IR[15:12],lowerop}, RAM_DO, regin_en, result_en, imm_data, imm_en, F, PSR_en, result, B);

//RAM(DI,DO,ADDR,CLK,RESET,WE,EN);
RAM RAMBLOCK1(result,RAM_DO,RAM_ADDR,CLK,reset,RAM_WE,1'b1);

//S3Etest S2eTest(CLK, reset, reg2_data, SF_CE0, SF_D, LCD_E, LCD_RS, LCD_RW);
lcd_ctrl LCD(CLK, reset, PC, SF_D, LCD_E, LCD_RS, LCD_RW);

always@(posedge CLK) begin
	if(reset) begin
		state <= boot;
		end
	else begin
		case(state)
			boot: state <= fetch;
			fetch: state <= decode;
			decode: begin
				state<=boot;
				if ({IR[15:12],IR[7:4]} == LOAD)
					state <= loadexecute;
				if ({IR[15:12],IR[7:4]} == STOR)
					state <= storexecute;
				if (IR[15:12] != 4'h0 && IR[15:12] != 4'h4 && IR[15:12] != 4'hc) //Immediate instruction
					state <= immediateexecute;
				if (IR[15:12] == 4'h0) 					//Rtype instruction
					state <= rtypeexecute;
				if ({IR[15:12],IR[7:4]} == 8'h4c)	//Jump conditional
					state <= jumpexecute;
			end
			
			jumpexecute: begin
			   state<=nojump;
				if (IR[11:8] == 4'b0000) begin //JEQ
					if (F[4]) state<=Jcondstate;
				end 
				if (IR[11:8] == 4'b0001) begin //JNE
					if (~F[4]) state<=Jcondstate;
				end
				if (IR[11:8] == 4'b0111) begin //JLE
					if (~F[1]) state<=Jcondstate;
				end
				if (IR[11:8] == 4'b1100) begin //JLT
					if (~F[4] & ~F[1]) state<=Jcondstate;
				end
				if (IR[11:8] == 4'b1101) begin //JGE
					if (F[4] | F[1]) state<=Jcondstate;
				end
				if (IR[11:8] == 4'b0110) begin //JGT
					if (F[1]) state<=Jcondstate;
				end
				if (IR[11:8] == 4'b1110) begin //JUC
					state<=Jcondstate;
				end
			end
			
			storexecute: state <= storstate;
			loadexecute: state <= loadstate;
			rtypeexecute: begin
				state <= rtypestore;
				if ({IR[15:12],IR[7:4]} == 8'b00001011)
					state <=cmpstore;
			end
			
			immediateexecute: begin
				state <= immediatestate;
				if (IR[15:12] == 4'b1011)
					state <= cmpstore;			
			end
			
			storstate: state <= fetch;
			loadstate: state <= boot;
			rtypestore: state <= boot;
			immediatestate: state <= boot;
			cmpstore: state <= boot;
			default: state <= boot;
			
	endcase
	
	end
end



always@(state) begin

	case(state)
	
	boot: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=0;
		IR_EN=0;
		PC_EN=1;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end
	
	fetch: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=0;
		IR_EN=1;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end

	decode: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end

//Execute
   rtypeexecute: begin	
		PSR_en=1;
		PC_Jump=0;
		PC_WE=0;
		result_en=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		RAM_WE=0;
	end
	
	loadexecute: begin
		PSR_en=1;
		PC_Jump=0;
		PC_WE=0;
		result_en=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		RAM_WE=0;
	end
	
	storexecute: begin
		PSR_en=1;
		PC_Jump=0;
		PC_WE=0;
		result_en=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		RAM_WE=0;
	end
	
	immediateexecute: begin
		PSR_en=1;
		PC_Jump=0;
		PC_WE=0;
		result_en=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=1;
		regin_en=0;
		RAM_WE=0;
	end
	 
	jumpexecute: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=0;
		result_en=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		RAM_WE=0;
	end

//Store type states
	storstate: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=1;
		result_en=1;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		RAM_WE=1;
	end


	loadstate: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=1;
		result_en=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=1;
		imm_en=0;
		regin_en=1;
		RAM_WE=0;
	end
	
	immediatestate: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=1;
		IR_EN=0;
		PC_EN=0;
		wr_en=1;
		imm_en=1;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end

	rtypestore: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=1;
		IR_EN=0;
		PC_EN=0;
		wr_en=1;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;	
	end
	
	Jcondstate: begin
		PSR_en=0;
		PC_Jump=1;
		PC_WE=1;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;		
	  end
	  
	nojump: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=1;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end
	
	cmpstore: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=1;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=1;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end
	
	default: begin
		PSR_en=0;
		PC_Jump=0;
		PC_WE=0;
		IR_EN=0;
		PC_EN=0;
		wr_en=0;
		imm_en=0;
		regin_en=0;
		result_en=0;
		RAM_WE=0;
	end
	
	endcase

end

endmodule
